//
// Define class QueryServer.
//

#ifndef __QUERY__SERVER__H
#define __QUERY__SERVER__H

#include <list>
#include <map>
#include <ext/hash_map>

#include "core/base/mutex.h"
#include "core/base/noncopyable.h"
#include "core/base/types.h"
#include "demo/http_server.h"

using namespace core;

namespace demo {

struct LocationEventNode {
  int longitude_;
  int latitude_;
  uint64 id_;
  std::string tag_;
  std::string sub_tag_;
};

struct LocationUserNode {
  int logitude_;
  int latitude_;
  uint64 id_;
};

struct UserLocationNode {
  time_t time_;
  int logitude_;
  int latitude_;
};

struct Coordinate {
  int x_;
  int y_;

  bool operator < (const Coordinate &coor) const {
    if(this->x_ == coor.x_) {
      return this->y_ < coor.y_;
    } else {
      return this->x_ < coor.x_;
    }
  }

  bool operator == (const Coordinate &coor) const {
    return this->x_ == coor.x_ && this->y_ == coor.y_;
  }
};

struct CoordinateHash {
  size_t operator()(const Coordinate &coor) const {
    uint64 k1 = (coor.x_ & 0xFFFFFFFFFFF) << 32;
    uint64 k2 = coor.y_;
    return k1 + k2;
  }
};

class QueryServer : public Noncopyable {
  typedef std::map<time_t, LocationEventNode> LocationEventMap;
  typedef std::map<time_t, LocationUserNode> LocationUserMap;
  typedef std::pair<LocationEventMap, LocationUserMap> LocationNode;
  typedef __gnu_cxx::hash_map<Coordinate, LocationNode, CoordinateHash> LocationHash;

  typedef std::list<UserLocationNode> UserLocationList;
  typedef __gnu_cxx::hash_map<uint64, UserLocationList> UserHash;

 public:
  QueryServer(uint64 user_ids, uint64 event_ids);
  ~QueryServer();

  void OnRequest(const HttpRequest& request, HttpResponse *response);

 private:
  bool AddEvent(const std::string &request, HttpResponse *response);
  bool AddUser(const std::string &request, HttpResponse *response);
  bool UpdateUser(const std::string &request, HttpResponse *response);
  bool GetUserPathPoint(const std::string &request, HttpResponse *response);
  bool GetUserList(const std::string &request, HttpResponse *response);
  bool GetEventList(const std::string &request, HttpResponse *response);
  bool DeleteEvent(const std::string &request, HttpResponse *response);

  uint64 SignInEvent(double longitude, double latitude,
    const std::string &tag_, const std::string &sub_tag_);
  uint64 SignInUser();
  bool UpdateUser(uint64 uid, double longitude, double latitude, time_t time);

  LocationHash locations_;
  UserHash users_;

  Mutex mutex_location_;
  Mutex mutex_user_;

  uint64 user_ids_;
  uint64 event_ids_;

  Mutex mutex_user_id_;
  Mutex mutex_event_id_;

  static const size_t kAddUserSize;
  static const char kAddUserStr[];
  static const char kAddEventStr[];
  static const char kUpdateUserStr[];
  static const char kGetUserPathPointStr[];
  static const char kGetUserListStr[];
  static const char kGetEventListStr[];
  static const char kDeleteEventStr[];
};

}  // namespace demo

#endif  // __QUERY__SERVER__H

